﻿using Candy.Infrastructure;
using Candy.Model;
using Candy.Web.Data;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;

namespace Candy.ViewModel
{
    public class JobViewModel : EntityViewModelBase<BlastJobDto>
    {
        private bool _isLoading;
        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }
            set
            {
                _isLoading = value;
                if (_isLoading)
                    base.ReportProgress();
                else
                    base.FinishProgress();
                RaisePropertyChanged("IsLoading");
            }
        }

        private bool _hasLoaded;
        public bool HasLoaded
        {
            get
            {
                return _hasLoaded;
            }
            set
            {
                _hasLoaded = value;
                RaisePropertyChanged("HasLoaded");
            }
        }

        private ObservableCollection<BlastHitViewModel> _hits;
        public ObservableCollection<BlastHitViewModel> Hits
        {
            get
            {
                return _hits;
            }
            set
            {
                _hits = value;
                RaisePropertyChanged("Hits");
            }
        }



        public string Name
        {
            get
            {
                return Entity.Name;
            }
        }


        IDataService _dataService;
        public JobViewModel(IDataService dataService, BlastJobDto dto)
            : base(dto)
        {
            _dataService = dataService;
            //cut and paste this line to your ctor
            _loadHits = new RelayCommand(ExecLoadHits, CanLoadHits);

            dto.PropertyChanged += dto_PropertyChanged;
        }

        void dto_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {

            if (e.PropertyName == "Status")
            {

            }
        }

        private RelayCommand _loadHits;
        public RelayCommand LoadHits
        {
            get
            {
                return _loadHits;
            }
        }

        /// <summary>
        /// Checks whether the LoadHits command is executable
        /// </summary>
        private bool CanLoadHits()
        {
            return !_isLoading && !_hasLoaded;
        }

        /// <summary>
        /// Executes the LoadHits command 
        /// </summary>
        private void ExecLoadHits()
        {
            base.ResetError();
            if (_isLoading == false)
            {
                Hits = new ObservableCollection<BlastHitViewModel>();
                if (Entity.Status == RequestStatus.RESULTS && Entity.EntityState != System.ServiceModel.DomainServices.Client.EntityState.Deleted)
                {
                    IsLoading = true;
                    _dataService.LoadBlastHitsAsync(Entity.Id, op =>
                       {
                           IsLoading = false;
                           if (!op.HasError)
                           {
                               HasLoaded = true;
                               var hits = from x in op.Entities orderby x.Expectation select new BlastHitViewModel(_dataService, x, Entity.Task);
                               Hits = new ObservableCollection<BlastHitViewModel>(hits);
                               CalculateHeatMap();
                           }
                           else
                           {
                               base.HandleDomainError(op, "Loading results failed.");
                           }

                       });
                }
            }
        }

        private void CalculateHeatMap()
        {
            if (_hits.Count > 0)
            {
                double? mi = _hits.Min(x => x.Entity.Expectation);
                double? ma = _hits.Max(x => x.Entity.Expectation);
                double min = (double)_hits.Min(x => x.Entity.Expectation);
                double max = (double)_hits.Max(x => x.Entity.Expectation);
                foreach (var item in _hits)
                {
                    item.Heat = new SolidColorBrush(HeatMapper.MapValue((double)item.Entity.Expectation, min, max, Colors.Green, Colors.Blue));
                }
            }
        }



        public bool AllowImportAll
        {
            get
            {
                return _dataService.LoadedProject.AllowImportAll;
            }

        }



        private volatile bool _isImportingAll;


        private RelayCommand _importAll;
        public RelayCommand ImportAll
        {
            get
            {
                return _importAll ?? (_importAll = new RelayCommand(ExecImportAll, CanImportAll));
            }
        }

        /// <summary>
        /// Checks whether the ImportAll command is executable
        /// </summary>
        private bool CanImportAll()
        {
            return !_isImportingAll && _dataService.LoadedProject.AllowImportAll;
        }


        AutoResetEvent _importEvent = new AutoResetEvent(false);

        /// <summary>
        /// Executes the ImportAll command 
        /// </summary>
        private void ExecImportAll()
        {
            base.ConfirmAction((doit) =>
                {
                    if (doit)
                    {
                        Task.Factory.StartNew(() =>
            {
                _isImportingAll = true;
                foreach (var item in this.Hits)
                {
                    item.ImportAsync(() =>
                        {
                            _importEvent.Set();
                        });
                    _importEvent.WaitOne();
                }

                _isImportingAll = false;
            });
                    }
                }, "With great power comes great responsibility.");
        }





    }
}
